import java.util.List;
import java.util.ArrayList;

public class InfiniteLine implements Shape {
	private double k, m;

	public InfiniteLine(Point p1, Point p2) {
		/** Coefficient of line, k:
		 *
		 *      Y1 - Y2
		 * k = ---------
		 *      X1 - X2
		 */
		this.k = (p1.getY() - p2.getY()) / (p1.getX() - p2.getX());

		/** Intersection with Y-axis, m:
		 *
		 * m = Y1 - k*X1
		 */
		this.m = p1.getY() - k*p1.getX();
	}
	public InfiniteLine(InfiniteLine line) {
		this.k = line.getK();
		this.m = line.getM();
	}
	public InfiniteLine(double k, double m) {
		this.k = k;
		this.m = m;
	}
	// Using this can cause nullpointer exceptions
	public InfiniteLine() { }
	
	/** Setters **/
	public void setK(double k) {
		this.k = k;
	}
	public void setM(double m) {
		this.m = m;
	}
	
	/** Getters **/
	public double getK() {
		return this.k;
	}
	public double getM() {
		return this.m;
	}
	
	// Given either X- or Y-coordinate, calculate the other
	public double getX(double y) {
		return (y-this.m)/this.k;
	}
	public double getY(double x) {
		return x*this.k + this.m;
	}

	// Returns the point where the lines intersects
	public List<Point> intersections(Shape other) {
		if(other instanceof InfiniteLine) {
			return intersections((InfiniteLine)other);
		} else {
			throw new NullPointerException();
		}
	}
	public List<Point> intersections(InfiniteLine line) {
		// Firstly, check so that the lines are not parallel - if they are, they don't _ever_ intersect
		if(this.getK() == line.getK())
			return null;	// Might want to throw() instead?

		/** X-coordinate for the intersection
		 *
		 *      M2 - M1
		 * x = ---------
		 *      K1 - K2
		 */

		double x = (line.getM() - this.getM()) / (this.getK() - line.getK());

		/** Insertion of x into the equation yields Y-coordiante
		 * y = k*x + m
		 */
		Point p = new Point(x, x*this.getK() + this.getM());
		List<Point> list = new ArrayList<Point>();
		list.add(p);
		return list;
	}
	
	// The area between this line and the X-axis from p1 to p2
	public double integral(Point p1, Point p2) {
		return integral(p1.getX(), p2.getX());
	}
	public double integral(double x1, double x2) {
		// Verify order of the given coordinates
		if(x1 > x2) {
			double tmp = x1;
			x1 = x2;
			x2 = tmp;
		}

		/** Area by computing the integral 
	     *
		 * Higher order function of k*x+m is (k/2)*x^2 + m*x
		 *
		 * A = k/2(x2^2 - x1^2) + m(x2 - x1)
		 */
		 return this.k/2*(x2*x2 - x1*x1) + this.m*(x2 - x1);
	}

	public String toString() {
		return "y = " + this.k + "x + " + this.m;
	}
}
